package cn.dengta.webapp.trade.model;

import java.util.LinkedList;
import java.util.List;
import javax.annotation.Nullable;

import cn.dengta.common.model.ValueProxy;
import cn.dengta.common.model.ValueProxyImpl;
import lombok.Getter;
import me.codeplayer.util.NumberUtil;
import me.codeplayer.util.X;
import org.apache.commons.lang3.tuple.Pair;

/**
 * 用户等级经验
 */
@Getter
public enum UserLevelType implements ValueProxyImpl<UserLevelType, Integer> {
	/** L0 */
	L0(0, 0L),
	/** L1 */
	L1(1, 800L),
	/** L2 */
	L2(2, 2000L),
	/** L3 */
	L3(3, 5000L),
	/** L4 */
	L4(4, 8000L),
	/** L5 */
	L5(5, 14000L),
	/** L6 */
	L6(6, 22000L),
	/** L7 */
	L7(7, 30000L),
	/** L8 */
	L8(8, 50000L),
	/** L9 */
	L9(9, 80000L),
	/** L10 */
	L10(10, 130000L),
	/** L11 */
	L11(11, 200000L),
	/** L12 */
	L12(12, 500000L),
	/** L13 */
	L13(13, 1000000L),
	//
	;
	public final Integer value;
	public final Long exp;
	final ValueProxy<UserLevelType, Integer> proxy;

	// 构造函数，枚举类型只能为私有
	UserLevelType(Integer value, Long exp) {
		this.value = value;
		this.exp = exp;
		this.proxy = new ValueProxy<>(this, value, name());
	}

	private static final UserLevelType[] CACHE = getValues();

	private static UserLevelType[] getValues() {
		return ValueProxy.getCachedArray(UserLevelType.class, UserLevelType::values);
	}

	/** 内部13级以内通过枚举计算 */
	private static Pair<Integer, Long> calcInnerLevel(final Long score) {
		UserLevelType level;
		if (score != null && score > 0) {
			UserLevelType[] values = CACHE;
			int length = values.length;
			for (int i = 0; i < length; i++) {
				level = values[i];
				if (level.exp > score) {
					level = values[i - 1];
					return Pair.of(level.getValue(), level.getExp());
				}
			}
			if (score >= (level = values[length - 1]).exp) {
				return Pair.of(level.getValue(), level.getExp());
			}
		}
		level = UserLevelType.L0;
		return Pair.of(level.getValue(), level.getExp());
	}

	public static Pair<Integer, Long> calcNextLevel(final Long score, @Nullable Pair<Integer, Long> pair) {
		if (pair == null) {
			pair = calcLevel(score);
		}
		Integer value = pair.getLeft();
		int diffLevel = value - CACHE.length;
		if (diffLevel >= 0) {
			List<Pair<Integer, Long>> levelCache = gt13LevelCache();
			return levelCache.get(Math.min(diffLevel + 1, X.size(levelCache) - 1));
		}
		UserLevelType nextLevel = of(value + 1);
		return Pair.of(nextLevel.getValue(), nextLevel.getExp());
	}

	private static UserLevelType of(Integer value) {
		return L0.getValueOf(value);
	}

	public static Integer calcLevelByAvatarLevel(int avatarLevel) {
		switch (avatarLevel) {
			case 1:
				return 4;
			case 2:
				return 5;
			default:
				return (avatarLevel - 2) * 10;
		}
	}

	/** 根据经验计算头像等级 */
	public static Integer calcAvatarLevelByExp(long exp, boolean query) {
		Pair<Integer, Long> pair = calcLevel(exp);
		Integer level = pair.getLeft();
		int avatarLevel = 0;
		if (UserLevelType.L4.eq(level)) {
			avatarLevel = 1;
		} else if (UserLevelType.L5.eq(level)) {
			avatarLevel = 2;
		} else if (level >= UserLevelType.L10.value && (query || level % 10 == 0)) {
			avatarLevel = Math.min(2 + level / 10, 10); // 目前最高10级头像
		}
		if (query && avatarLevel <= 0 && level > UserLevelType.L5.value) {
			avatarLevel = 2;
		}
		return avatarLevel;
	}

	/** 计算可存在的头像等级 Pair<old, new> */
	public static Pair<Integer, Integer> calcAvatarRangeLevelByExp(long oldExp, long newExp) {
		Integer oldLevel = calcAvatarLevelByExp(oldExp, true);
		Integer newLevel = calcAvatarLevelByExp(newExp, true);
		return (newLevel - oldLevel) > 0 ? Pair.of(Math.max(oldLevel, 1), newLevel) : null;
	}

	public static Pair<Integer, Long> calcLevel(final Long score) {
		if (score != null && score > UserLevelType.L13.exp) {
			List<Pair<Integer, Long>> levelCache = gt13LevelCache();
			int length = X.size(levelCache);
			Pair<Integer, Long> level;
			for (int i = 0; i < length; i++) {
				level = levelCache.get(i);
				if (level.getRight() > score) {
					return i > 0 ? levelCache.get(i - 1) : Pair.of(UserLevelType.L13.getValue(), UserLevelType.L13.getExp());
				}
			}
			if (score >= (level = levelCache.get(length - 1)).getRight()) {
				return level;
			}
		}
		return calcInnerLevel(score);
	}

	private static List<Pair<Integer, Long>> gt13LevelCache;

	private static List<Pair<Integer, Long>> gt13LevelCache() {
		List<Pair<Integer, Long>> levelCache = gt13LevelCache;
		if (levelCache == null) {
			double nextExp = UserLevelType.L13.getExp();
			int value = UserLevelType.L13.value;
			levelCache = new LinkedList<>();
			for (int i = 0; i < 67; i++) {
				nextExp = nextExp * 1.1;
				levelCache.add(Pair.of(++value, NumberUtil.getLong(nextExp)));
			}
			gt13LevelCache = levelCache;
		}
		return levelCache;
	}
}
